Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | /** * API route for skill metrics * * GET /api/curriculum/[playerId]/skills/metrics * Returns computed skill metrics for scoreboard display. */ import { NextResponse } from 'next/server' import { and, desc, eq, inArray } from 'drizzle-orm' import { db } from '@/db' import * as schema from '@/db/schema' import { withAuth } from '@/lib/auth/withAuth' import { canPerformAction } from '@/lib/classroom' import { computeStudentSkillMetrics } from '@/lib/curriculum/skill-metrics' import { getRecentSessionResults } from '@/lib/curriculum/session-planner' import { getUserId } from '@/lib/viewer' /** * GET /api/curriculum/[playerId]/skills/metrics * Get computed skill metrics for a player. * * These metrics are computed on-the-fly from session results: * - Overall mastery (weighted average of pKnown) * - Category breakdown (basic, fiveComplements, etc.) * - Normalized response time (seconds per term) * - Accuracy trends * - Progress metrics (improvement rate, streak, problem counts) */ export const GET = withAuth(async (_request, { params }) => { const { playerId } = (await params) as { playerId: string } try { // Authorization check const userId = await getUserId() const canView = await canPerformAction(userId, playerId, 'view') if (!canView) { return NextResponse.json({ error: 'Not authorized' }, { status: 403 }) } // Get problem results for BKT computation (last 100 sessions for comprehensive history) const results = await getRecentSessionResults(playerId, 100) // Get session plans for streak calculation const sessions = await db.query.sessionPlans.findMany({ where: and( eq(schema.sessionPlans.playerId, playerId), inArray(schema.sessionPlans.status, ['completed', 'abandoned']) ), orderBy: [desc(schema.sessionPlans.completedAt)], limit: 100, }) // Compute metrics const metrics = computeStudentSkillMetrics(results, sessions) return NextResponse.json({ metrics }) } catch (error) { console.error('Error fetching skill metrics:', error) return NextResponse.json({ error: 'Failed to fetch skill metrics' }, { status: 500 }) } }) |